#ifndef EPOLLER
#define EPOLLER

#include <sys/poll.h>
#include <sys/epoll.h>
#include <sys/select.h>
#include "Socket.hpp"

class Poller
{
public:
    static constexpr int size = sizeof(void *) * sizeof(fd_set);
};

class Select : public Poller
{
public:
private:
    // 管理fd
    int fd[size];
};

class Poll : public Poller
{
public:
private:
    struct pollfd _fds[size];
};

class Epoll : public Poller
{
    const static int defaultfd = -1;
    const static int defaultsize = 128;

public:
    Epoll() : _epfd(defaultfd)
    {
        _epfd = epoll_create(defaultsize);
        // 处理错误
        if (_epfd < 0)
        {
            LogModule::LOG(FATAL) << "_epfd create error";
            exit(EPOLL_CREATE_ERR);
        }
        LogModule::LOG(INFO) << "_epfd create success";
    }

    void ModEventHelper(int sockfd, uint32_t events, uint32_t op /**表示这是什么操作，add，del，mod */)
    {
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = sockfd;
        int n = epoll_ctl(_epfd, op, sockfd, &ev);
        if (n < 0)
        {
            LogModule::LOG(ERROR) << "epoll ctl error";
            return;
        }
        else if (n == 0)
        {
            LogModule::LOG(DEBUG) << "epoll ctl success";
        }
        else
        {
            // TODO
        }
    }

    // 添加对fd上某一事件的关心
    void AddEvent(int sockfd, uint32_t events)
    {
        ModEventHelper(sockfd, events, EPOLL_CTL_ADD);
    }

    // 移除对fd上某一事件的关心
    void DelEvent(int sockfd, uint32_t events)
    {
        ModEventHelper(sockfd, events, EPOLL_CTL_DEL);
    }

    // 修改对fd上某一事件的关心
    void ModEvent(int sockfd, uint32_t events)
    {
        ModEventHelper(sockfd, events, EPOLL_CTL_MOD);
    }

    // 就绪fd的数量
    int WaitEvent(struct epoll_event revs[], int max_events, int timeout)
    {
        int n = epoll_wait(_epfd, revs, max_events, timeout);
        if (n < 0)
        {
            LogModule::LOG(ERROR) << "epoll_wait wait error";
            // return -1;
        }
        else if (n == 0)
        {
            LogModule::LOG(DEBUG) << "epoll_wait timeout";
            // return n;
        }
        else
        {
            // TODO
        }
        // LogModule::LOG(DEBUG) << "epoll wait success";
        return n;
    }

    ~Epoll()
    {
        if (_epfd > 0)
            ::close(_epfd);
    }

private:
    int _epfd;
};

#endif